-- local KleeU = require "packages/gm_mahjong/utility/k_utility"

---@class KleeU
local KleeU = {}

--万(m)饼(p)条(s)字(z)
--东(1z)南(2z)西(3z)北(4z)白(5z)发(6z)中(7z)
--红宝牌(0m、0p、0s)，但暂无

--牌名和图片的命名规则为："mahjong_" .. suit .. number
--如三饼为：mahjong_p3

Fk:loadTranslationTable{
  ["Mahjong_East"] = "东风",
  ["Mahjong_West"] = "西风",
  ["Mahjong_South"] = "南风",
  ["Mahjong_North"] = "北风",
  ["Mahjong_RedDragon"] = "红中",
  ["Mahjong_GreenDragon"] = "发财",
  ["Mahjong_WhiteDragon"] = "白板",
  ["Mahjong_One"] = "一",
  ["Mahjong_Two"] = "二",
  ["Mahjong_Three"] = "三",
  ["Mahjong_Four"] = "四",
  ["Mahjong_Five"] = "五",
  ["Mahjong_Six"] = "六",
  ["Mahjong_Seven"] = "七",
  ["Mahjong_Eight"] = "八",
  ["Mahjong_Nine"] = "九",
  ["Mahjong_Dot"] = "筒",
  ["Mahjong_Bamboo"] = "条",
  ["Mahjong_Wan"] = "万",
  ["Mahjong_Dora"] = "宝牌",
  ["Mahjong_One_Mahjong_Bamboo"] = "幺鸡",


  ["Mahjong_Riichi"] = "立直",
  ["Mahjong_All_Simples"] = "断幺九",
  ["Mahjong_Full_Concealed_Hand"] = "门前清自摸和",
  ["Mahjong_Seat_Pung"] = "自风牌",
  ["Mahjong_Prevalent_Pung"] = "场风牌",
  ["Mahjong_Dragon_Pung"] = "三元牌",
  ["Mahjong_All_Chows"] = "平和",
  ["Mahjong_Pure_Double_Chow"] = "一杯口",
  ["Mahjong_Robbing_the_Kong"] = "抢杠",
  ["Mahjong_Out_with_Replacement_Tile"] = "岭上开花",
  ["Mahjong_Last_Tile_Draw"] = "海底摸月",
  ["Mahjong_Last_Tile_Claim"] = "河底捞鱼",
  ["Mahjong_Ippatsu"] = "一发",
  ["Mahjong_Red_Dora"] = "赤宝牌",
  ["Mahjong_Kita_Dora"] = "北宝牌",
  ["Mahjong_Double_Riichi"] = "两立直",
  ["Mahjong_Triple_Pung"] = "三色同刻",
  ["Mahjong_Three_Kongs"] = "三杠子",
  ["Mahjong_All_Pungs"] = "对对和",
  ["Mahjong_Three_Concealed_Pungs"] = "三暗刻",
  ["Mahjong_Little_Three_Dragons"] = "小三元",
  ["Mahjong_All_Terminals_and_Honors"] = "混老头",
  ["Mahjong_Seven_Pairs"] = "七对子",
  ["Mahjong_Half_Outside_Hand"] = "混全带幺九",
  ["Mahjong_Pure_Straight"] = "一气通贯",
  ["Mahjong_Mixed_Triple_Chows"] = "三色同顺",
  ["Mahjong_Two_Double_Chows"] = "二杯口",
  ["Mahjong_Pure_Outside_Hand"] = "纯全带幺九",
  ["Mahjong_Half_Flush"] = "混一色",
  ["Mahjong_Full_Flush"] = "清一色",
  ["Mahjong_Nagashi_Mangan"] = "流局满贯",
  ["Mahjong_Blessing_of_Heaven"] = "天和",
  ["Mahjong_Blessing_of_Earth"] = "地和",
  ["Mahjong_Big_Three_Dragons"] = "大三元",
  ["Mahjong_Four_Concealed_Pungs"] = "四暗刻",
  ["Mahjong_All_Honors"] = "字一色",
  ["Mahjong_All_Green"] = "绿一色",
  ["Mahjong_All_Terminals"] = "清老头",
  ["Mahjong_Thirteen_Orphans"] = "国士无双",
  ["Mahjong_Little_Four_Winds"] = "小四喜",
  ["Mahjong_Four_Kongs"] = "四杠子",
  ["Mahjong_Nine_Gates"] = "九莲宝灯",
  ["Mahjong_Single-Wait_Four_Concealed_Pungs"] = "四暗刻单骑",
  ["Mahjong_All-Wait_Thirteen_Orphans"] = "国士无双十三面",
  ["Mahjong_True_Nine_Gates"] = "纯正九莲宝灯",
  ["Mahjong_Big_Four_Winds"] = "大四喜",
}

KleeU.Yaku = {
  [1] = {"Mahjong_Riichi", "Mahjong_All_Simples", "Mahjong_Full_Concealed_Hand", 
    "Mahjong_Prevalent_Pung", "Mahjong_Seat_Pung", "Mahjong_Dragon_Pung", "Mahjong_All_Chows", 
    "Mahjong_Pure_Double_Chow", "Mahjong_Robbing_the_Kong", "Mahjong_Out_with_Replacement_Tile", 
    "Mahjong_Last_Tile_Draw", "Mahjong_Last_Tile_Claim", "Mahjong_Ippatsu"},
  [2] = {"Mahjong_Double_Riichi", "Mahjong_Triple_Pung", "Mahjong_Three_Kongs", 
    "Mahjong_All_Pungs", "Mahjong_Three_Concealed_Pungs", "Mahjong_Little_Three_Dragons",
    "Mahjong_All_Terminals_and_Honors", "Mahjong_Seven_Pairs", "Mahjong_Half_Outside_Hand",
    "Mahjong_Pure_Straight", "Mahjong_Mixed_Triple_Chows"},
  [3] = {"Mahjong_Twice_All_Chows", "Mahjong_Pure_Outside_Hand", "Mahjong_Half_Flush"},
  [6] = {"Mahjong_Full_Flush"},
  ["Mangan"] = {"Mahjong_Nagashi_Mangan"},
  ["Yakuman"] = {"Mahjong_Blessing_of_Heaven", "Mahjong_Blessing_of_Earth", 
    "Mahjong_Big_Three_Dragons", "Mahjong_Four_Concealed_Pungs", "Mahjong_All_Honors", 
    "Mahjong_All_Green", "Mahjong_All_Terminals", "Mahjong_Thirteen_Orphans", 
    "Mahjong_Little_Four_Winds", "Mahjong_Four_Kongs", "Mahjong_Nine_Gates"},
  ["Double_Yakuman"] = {"Mahjong_Single-Wait_Four_Concealed_Pungs", "Mahjong_Thirteen_Orphans", 
    "Mahjong_True_Nine_Gates", "Mahjong_Big_Four_Winds"}
}

KleeU.suits = {"m", "s", "p", "z"}
KleeU.suits_without_z = {"m","s","p"}

--- 麻将牌（记录牌面和牌的种类和对应的牌的id）
---@class KleeU.Mahjong : Object
---@field suit "m"|"p"|"s"|"z" @万|饼|条|字
---@field number integer @点数
---@field dora boolean @是否是宝牌
---@field id integer @对应卡牌id
---@field getCardName fun(self: KleeU.Mahjong): string @获得卡牌的名称
---@field getCardTrans fun(self: KleeU.Mahjong): string @获得卡牌的中文译名

KleeU.Mahjong = class("Mahjong")

---初始化
---@param card Card|integer|string 卡牌或麻将牌类型
---@param number integer?
---@param dora boolean?
---@return KleeU.Mahjong
function KleeU.Mahjong:initialize(card, number, dora)
  if not card or (not number and card == 0) then
    self.suit = 0
    self.number = 0
    self. dora = false
    self.id = 0
  elseif not number then
    local c
    if type(card) == "number" then
      c = Fk:getCardById(card)
    else
      c = card
    end
    self.suit = KleeU.suits[c.suit - 5]
    self.number = c.suit == 0 and 5 or c.suit - 13
    self.dora = c.number == 0
    self.id = c.id
  else
    self.suit = card
    self.number = number
    self.dora = dora
    self.id = 0
  end
end


---获得卡牌的名称
---@param self KleeU.Mahjong
---@return string
function KleeU.Mahjong:getCardName()
  return "mahjong_" .. self.suit .. (self.dora and 0 or self.number)
end

---获得卡牌的中文译名
---@param self KleeU.Mahjong
---@return string
function KleeU.Mahjong:getCardTrans()
  return KleeU.getTrans(self.suit, self.number, self.dora)
end

--- 通过点数和花色获取中文名
---@param suit string|integer
---@param number integer
---@return string
KleeU.getTrans = function(suit, number, dora)
  if type(suit) == "number" then
    suit = KleeU.suits[suit]
  end
  dora = dora or false
  local name
  if suit == "z" then
    if number == 1 then
      name = "Mahjong_East"
    elseif number == 2 then
      name = "Mahjong_South"
    elseif number == 3 then
      name = "Mahjong_West"
    elseif number == 4 then
      name = "Mahjong_North"
    elseif number == 5 then
      name = "Mahjong_WhiteDragon"
    elseif number == 6 then
      name = "Mahjong_GreenDragon"
    elseif number == 7 then
      name = "Mahjong_RedDragon"
    else
      return "<font color='#BE2020'>未知字牌</font>"
    end
    return Fk:translate(name)
  end 
  if number == 1 then
    name = "One"
  elseif number == 2 then
    name = "Two"
  elseif number == 3 then
    name = "Three"
  elseif number == 4 then
    name = "Four"
  elseif number == 5 then
    name = "Five"
  elseif number == 6 then
    name = "Six"
  elseif number == 7 then
    name = "Seven"
  elseif number == 8 then
    name = "Eight"
  elseif number == 9 then
    name = "Nine"
  else
    return "<font color='#BE2020'>未知点数</font>"
  end
  name = Fk:translate("Mahjong_" .. name)
  if suit == "m" then
    name = name .. Fk:translate("Mahjong_Wan")
  elseif suit == "p" then
    name = name .. Fk:translate("Mahjong_Dot")
  elseif suit == "s" then
    if number == 1 then
      name = Fk:translate("Mahjong_One_Mahjong_Bamboo")
    end
    name = name .. Fk:translate("Mahjong_Bamboo")
  else
    return "<font color='#BE2020'>未知类型</font>"
  end

  if dora then
    name = name .. Fk:translate("Mahjong_Dora")
  end

  return name
end


--- 获得牌的吃碰杠信息（标记）
--- 0-否 1-吃 2-碰 3-杠 4-明杠 5-暗杠
--- @param card Card|integer
--- @return integer
KleeU.getCardCPK = function (card)
  local c ---@type Card
  if type(card) == "number" then
    c = Fk:getCardById(card)
  elseif type(card) == "table" then
    c = card
  end

  if c:getMark("@@Chow") > 0 then
    return 1
  elseif c:getMark("@@Pung") > 0 then
    return 2
  elseif c:getMark("@@Kong") > 0 or c:getMark("@@Kong-Hide") > 0 then
    return 3
  elseif c:getMark("@@Kong") > 0 then
    return 4
  elseif c:getMark("@@Kong-Hide") > 0 then
    return 5
  end
  return 0
end

--- 获得手牌
--- 0-可用 1-吃 2-碰 3-杠
--- @param player Player
--- @param kind? integer
--- @return integer[]
KleeU.getHandCards = function (player, kind)
  kind = kind or 0
  return table.filter(player:getCardIds("h"), function (cid)
    return KleeU.getCardCPK(cid) == kind
  end)
end

---获得玩家一张手牌的状态
---@param cid integer|Card @手牌id
---@return integer,integer @状态，对应index 状态：-1-未知 0-手牌 1-吃 2-碰 3-明杠 4-暗杠
KleeU.getCardState = function (cid)
  local c ---@type Card
  if type(cid) == "number" then
    c = Fk:getCardById(cid)
  elseif type(cid) == "table" then
    c = cid
  end
  
  if not cid then return -1, 0 end

  if c:getMark("@@Chow") > 0 then
    return 1, c:getMark("@@Chow")
  elseif c:getMark("@@Pung") > 0 then
    return 1, c:getMark("@@Pung")
  elseif c:getMark("@@Kong") > 0 then
    return 1, c:getMark("@@Kong")
  elseif c:getMark("@@Kong-Hide") > 0 then
    return 1, c:getMark("@@Kong-Hide")
  end
  return 0, 0
end

---获得副露的牌的分组
---@param player Player
---@return table[]
KleeU.getShownCardShapes = function(player)
  local cids = player:getCardIds(Player.Hand)
  local sets = {}
  local types = {"c", "p", "k", "kh"}
  local nowSet = {}
  for i = 1,4,1 do
    table.filter(cids, function (cid)
      local t,index = KleeU.getCardState(cid)
      if index == i then
        if #nowSet == 10 then
          table.insert(nowSet, types[t])
        end
        table.insert(nowSet, cid)
      end
    end)
  end
  return sets
end


---将原版卡牌转换成麻将牌格式
---@param card integer|Card @卡牌
---@return KleeU.Mahjong
KleeU.convertMahjong = function (card)
  return KleeU.Mahjong:new(card)
end

---将卡牌切分成33332类型并分组{{"c",...},...{"p",...},...,{"q",a,b}}[]
---@param cards KleeU.Mahjong[] @卡牌ID数组或Card对象数组
---@return table[] @所有可能的基本型切分结果
KleeU.basicShape = function(cards)
  -- 转换为Mahjong对象数组
  local mahjongs = cards

  -- 按花色和点数排序
  table.sort(mahjongs, function(a, b)
    if a.suit ~= b.suit then
      return a.suit < b.suit
    end
    return a.number < b.number
  end)

  local results = {}
  local current = {}

  -- 统计每种牌的数量
  local countMap = {}
  for _, mj in ipairs(mahjongs) do
    local key = mj.suit .. "_" .. mj.number
    countMap[key] = (countMap[key] or 0) + 1
  end

  -- 递归查找所有可能的切分
  local function findCombinations(remaining, startIdx, pairsUsed)
    if #remaining == 0 then
      table.insert(results, { table.unpack(current) })
      return
    end

    -- 如果已经找到4组，剩下的必须是一对
    if #current == 4 then
      if #remaining == 2 and remaining[1].suit == remaining[2].suit and
          remaining[1].number == remaining[2].number then
        local temp = table.simpleClone(current)
        table.insert(temp, { "q", remaining[1], remaining[2] })
        table.insert(results, temp)
      end
      return
    end

    -- 尝试所有可能的起始位置
    for i = startIdx, #remaining do
      -- 跳过已处理的牌
      if i > startIdx and remaining[i].suit == remaining[i - 1].suit and
          remaining[i].number == remaining[i - 1].number then
        goto continue
      end

      -- 尝试刻子 (三张相同的牌)
      if i <= #remaining - 2 and
          remaining[i].suit == remaining[i + 1].suit and remaining[i].suit == remaining[i + 2].suit and
          remaining[i].number == remaining[i + 1].number and remaining[i].number == remaining[i + 2].number then
        local triplet = { remaining[i], remaining[i + 1], remaining[i + 2] }
        table.insert(current, { "p", table.unpack(triplet) })

        local newRemaining = table.simpleClone(remaining)
        table.remove(newRemaining, i + 2)
        table.remove(newRemaining, i + 1)
        table.remove(newRemaining, i)

        findCombinations(newRemaining, math.max(1, i - 2), pairsUsed)

        table.remove(current)
      end

      -- 尝试顺子 (三张连续的同花色牌)
      if remaining[i].suit ~= "z" then       -- 字牌不能组成顺子
        local foundIndices = {}
        table.insert(foundIndices, i)

        -- 查找后续的连续牌
        for num = remaining[i].number + 1, remaining[i].number + 2 do
          local found = false
          for j = i + 1, #remaining do
            if remaining[j].suit == remaining[i].suit and
                remaining[j].number == num and
                not table.contains(foundIndices, j) then
              table.insert(foundIndices, j)
              found = true
              break
            end
          end
          if not found then
            break
          end
        end

        -- 如果找到顺子
        if #foundIndices == 3 then
          table.sort(foundIndices)
          local sequence = {
            remaining[foundIndices[1]],
            remaining[foundIndices[2]],
            remaining[foundIndices[3]]
          }

          table.insert(current, { "c", table.unpack(sequence) })

          local newRemaining = table.simpleClone(remaining)
          for idx = #foundIndices, 1, -1 do
            table.remove(newRemaining, foundIndices[idx])
          end

          findCombinations(newRemaining, math.max(1, i - 2), pairsUsed)

          table.remove(current)
        end
      end

      -- 尝试对子 (只在尚未使用对子时)
      if not pairsUsed and i <= #remaining - 1 and
          remaining[i].suit == remaining[i + 1].suit and
          remaining[i].number == remaining[i + 1].number then
        local pair = { remaining[i], remaining[i + 1] }
        table.insert(current, { "q", table.unpack(pair) })

        local newRemaining = table.simpleClone(remaining)
        table.remove(newRemaining, i + 1)
        table.remove(newRemaining, i)

        findCombinations(newRemaining, math.max(1, i - 2), true)

        table.remove(current)
      end

      ::continue::
    end
  end

  -- 开始查找
  findCombinations(mahjongs, 1, false)

  -- 过滤重复结果
  local uniqueResults = {}
  local seen = {}

  for _, result in ipairs(results) do
    -- 生成唯一标识符
    local keyParts = {}
    for _, group in ipairs(result) do
      local groupKey = group[1] .. "_"
      if group[1] == "q" then
        groupKey = groupKey .. group[2].suit .. group[2].number
      else
        -- 对刻子和顺子排序以确保一致性
        local items = {}
        for i = 2, #group do
          table.insert(items, group[i].suit .. group[i].number)
        end
        table.sort(items)
        groupKey = groupKey .. table.concat(items, "_")
      end
      table.insert(keyParts, groupKey)
    end
    table.sort(keyParts)
    local key = table.concat(keyParts, "|")

    if not seen[key] then
      seen[key] = true
      
      table.insert(uniqueResults, table.map(result, function (r)
        if type(r) ~= "string" then
          return r.id
        else
          return r
        end
      end))
    end
  end

  return uniqueResults
end

---检测该卡牌组合是否满足33332构型
---@param cards integer[]|Card[]
---@return boolean
KleeU.checkBasicShape = function(cards)
  -- 转换为Mahjong对象数组
  local mahjongs = table.map(cards, KleeU.convertMahjong)
  
  -- 如果牌数不是14张，直接返回false
  if #mahjongs ~= 14 then
    return false
  end

  -- 按花色和点数排序
  table.sort(mahjongs, function(a, b)
    if a.suit ~= b.suit then
      return a.suit < b.suit
    end
    return a.number < b.number
  end)

  -- 统计每种牌的数量
  local countMap = {}
  for _, mj in ipairs(mahjongs) do
    local key = mj.suit .. "_" .. mj.number
    countMap[key] = (countMap[key] or 0) + 1
  end

  -- 尝试所有可能的将牌（对子）
  local possiblePairs = {}
  for key, count in pairs(countMap) do
    if count >= 2 then
      table.insert(possiblePairs, key)
    end
  end

  -- 如果没有可能的将牌，直接返回false
  if #possiblePairs == 0 then
    return false
  end

  -- 检查剩余牌是否能组成4组刻子或顺子
  local function canFormGroups(remainingCount)
    -- 复制一份计数表，避免修改原表
    local tempCount = table.simpleClone(remainingCount)
    
    local groupsFound = 0
    
    -- 优先移除刻子（三张相同的牌）
    for key, count in pairs(tempCount) do
      if count >= 3 then
        tempCount[key] = count - 3
        groupsFound = groupsFound + 1
      end
    end
    
    -- 然后尝试顺子（三张连续的同花色牌）
    local suits = {"m", "p", "s"} -- 万、筒、索（字牌不能组成顺子）
    
    for _, suit in ipairs(suits) do
      for num = 1, 7 do  -- 顺子最多从7开始（7,8,9）
        local found = true
        while found do
          found = false
          -- 检查连续三张牌是否存在
          local key1 = suit .. "_" .. num
          local key2 = suit .. "_" .. (num + 1)
          local key3 = suit .. "_" .. (num + 2)
          
          if tempCount[key1] and tempCount[key1] > 0 and
             tempCount[key2] and tempCount[key2] > 0 and
             tempCount[key3] and tempCount[key3] > 0 then
            -- 移除顺子
            tempCount[key1] = tempCount[key1] - 1
            tempCount[key2] = tempCount[key2] - 1
            tempCount[key3] = tempCount[key3] - 1
            groupsFound = groupsFound + 1
            found = true
          end
        end
      end
    end
    
    -- 检查是否所有牌都被使用（组成4组）
    for _, count in pairs(tempCount) do
      if count ~= 0 then
        return false
      end
    end
    
    return groupsFound == 4
  end

  -- 尝试每一种可能的将牌
  for _, pairKey in ipairs(possiblePairs) do
    -- 复制一份计数表
    local tempCount = table.simpleClone(countMap)
    
    -- 移除将牌（对子）
    tempCount[pairKey] = tempCount[pairKey] - 2
    
    -- 检查剩余牌是否能组成4组
    if canFormGroups(tempCount) then
      return true
    end
  end

  return false
end

---检测麻将牌是否满足七对子
---@param cards KleeU.Mahjong[]
KleeU.checkSevenPairs = function (cards)
  if #cards ~= 14 then
    return false
  end
  
  -- 统计每种牌的数量
  local countMap = {}
  for _, card in ipairs(cards) do
    local key = card:getCardName()
    countMap[key] = (countMap[key] or 0) + 1
  end
  
  for _, count in pairs(countMap) do
    if count ~= 2 and count ~= 0 then
      return false -- 有单张或三张的牌
    end
  end
  return true
end

---判断是否符合国士无双牌型
---@param cards KleeU.Mahjong[]
---@return boolean
KleeU.checkThirteenOrphans = function (cards)
  -- 国士无双需要的牌型：1m,9m,1p,9p,1s,9s,1z,2z,3z,4z,5z,6z,7z + 任意一张这些牌
  local requiredTiles = {
    {suit = "m", number = 1},
    {suit = "m", number = 9},
    {suit = "p", number = 1},
    {suit = "p", number = 9},
    {suit = "s", number = 1},
    {suit = "s", number = 9},
    {suit = "z", number = 1},
    {suit = "z", number = 2},
    {suit = "z", number = 3},
    {suit = "z", number = 4},
    {suit = "z", number = 5},
    {suit = "z", number = 6},
    {suit = "z", number = 7}
  }
  
  for _, reqTile in ipairs(requiredTiles) do
    local found = false
    for _, card in ipairs(cards) do
      if card.suit == reqTile.suit and card.number == reqTile.number then
        found = true
        break
      end
    end
    if not found then
      return false
    end
  end
  
  -- 检查是否有一张额外的牌（必须是必需牌之一）
  if #cards == 14 then
    for _, card in ipairs(cards) do
      local isExtra = true
      for _, reqTile in ipairs(requiredTiles) do
        if card.suit == reqTile.suit and card.number == reqTile.number then
          isExtra = false
          break
        end
      end
      if isExtra then
        return false -- 包含非必需牌
      end
    end
    return true -- 14张牌且都是必需牌
  end
  
  return false
end

---检测玩家于出牌阶段能否暗杠
---@param player Player
---@return KleeU.Mahjong[]
KleeU.checkHideKong = function (player)
  local cards = KleeU.getHandCards(player, 0)
  local cardtable = {}
  for _, cid in ipairs(cards) do
    local c = Fk:getCardById(cid)
    local name = KleeU.convertMahjong(cid):getCardName()
    cardtable[name] = (cardtable[name] or {})
    table.insert(cardtable[name], name)
  end

  local kongs = {}
  -- 检测杠（需要4张相同牌）
  for _, count in pairs(cardtable) do
    if #count == 4 then
      table.insert(kongs, count)
    end
  end

  return kongs
end


---检测玩家于出牌阶段是否能加杠
---@param player Player
KleeU.checkAddKong = function (player)
  local cards = table.map(KleeU.getHandCards(player, 0), KleeU.convertMahjong)
  local kotsu = table.map(KleeU.getHandCards(player, 2), KleeU.convertMahjong)
  for _, cid in ipairs(kotsu) do
    if table.find(cards, function (mj)
      return mj.suit == cid.suit and mj.number == cid.number
    end) then
      return true
    end
  end
end

---检测玩家于出牌阶段是否能立直
---@param player Player
---@return boolean
KleeU.checkRichi = function (player)
  if #player:getHandcardNum() ~= #KleeU.getHandCards(player, 0) then return false end
  local cards = table.map(KleeU.getHandCards(player, 0), KleeU.convertMahjong)
  return player:getMark("@mahjong_point") >= 1000 and 
    (KleeU.checkSevenPairs(cards) or KleeU.checkThirteenOrphans(cards) or KleeU.checkBasicShape(cards))
end

---检测玩家于出牌阶段是否能自摸
---@param player Player
---@param cid integer
---@return boolean?
KleeU.checkZimo = function (player, cid)
  local maj= KleeU.convertMahjong(cid)
  
  return KleeU.findYaku(player, cid, 2)
end

---判断玩家加上摸上来的那张牌是否能形成役
---@param player Player
---@param cid integer @摸上来的卡牌的id
---@param from integer? @0-吃其他角色的牌 1-抢杠 2-自摸
---@return boolean
KleeU.findYaku = function (player, cid, from)
  from = from or 0
  local hide_cards = table.map(KleeU.getHandCards(player, 0), KleeU.convertMahjong)
  
  
  if from == 0 then
    table.insert(hide_cards, KleeU.convertMahjong(cid))
  end
  local hide_sets = KleeU.basicShape(hide_cards)
  if #hide_sets == 0 then
    return false
  end
  --门清的情况下 检查七对子、国士、正常胡
  if #hide_cards == 14 then
    return KleeU.checkThirteenOrphans(hide_cards) or KleeU.checkSevenPairs(hide_cards) 
      or #hide_sets > 0
  end
  --摸月捞鱼岭上抢杠
  if #Fk:currentRoom().draw_pile == 0 or from == 1 or player:getMark("Mahjong_Out_with_Replacement_Tile") > 0 then
    return KleeU.checkThirteenOrphans(hide_cards) or KleeU.checkSevenPairs(hide_cards) 
      or #hide_sets > 0
  end
  --不副露的牌切分（332）
  --副露的牌的切分
  local shown_sets = KleeU.getShownCardShapes(player)
  for _, hide_set in ipairs(hide_sets) do
    
  end
    --断幺九或全带幺九一系列的和牌
    --清一色
    --对对和
    --场风 自风 三元
    --三色同刻

    --三杠子
    --三色同顺
    --一气通贯

    --三暗刻
  return false
end

---判断玩家是否打出过此牌
---@param player Player
---@param mahjong KleeU.Mahjong
KleeU.getPlayerHistroy = function(player, mahjong)
  
end


---@deprecated
---检测玩家出牌时能执行的操作
---@param player Player
---@return string[]
KleeU.checkAction = function(player)
  local r = {}
  local ting = false
  local cards = table.map(KleeU.getHandCards(player, 0), KleeU.convertMahjong)
  local cardtable = {}
  for _, c in ipairs(cards) do
    local transName = c:getCardName()
    cardtable[transName] = (cardtable[transName] or 0) + 1
  end
  
  -- 检测杠（需要4张相同牌）
  for _, count in pairs(cardtable) do
    if count >= 4 then
      table.insert(r, "interaction_kong")
      break
    end
  end
  
  if ting then
    table.insert(r, "interaction_richi")
  end

  if KleeU.ifRong(player, nil) then
    table.insert(r, "interaction_zimo")
  end

  return r
end

--- 判断一张牌是否能与某人成吃碰杠
--- @param player Player
--- @param cid Card|integer
--- @return table<string, table<integer[]>> @包含吃(C)、碰(P)、杠(K)所有可能组合的表格
--- @deprecated
KleeU.ifCardCanCPK = function(player, cid)
  local result = {
    C = {}, -- 吃的组合
    P = {}, -- 碰的组合
    K = {}  -- 杠的组合
  }
  return result
end
---获得花色
---@param card any
---@return "m"|"p"|"s"|"z"
---@deprecated
KleeU.getSuit = function(card)
  return KleeU.convertMahjong(card).suit
end

-- 检查玩家听牌状态
--- @param player Player @要检查的玩家
--- @param cid integer|nil @如果为nil，检查当前手牌是否听牌；如果为数字，表示打出一张牌后是否听牌
--- @param require_menchin boolean? @是否需要门清
--- @return table @听的牌列表，每个元素为{suit=花色, number=点数}
KleeU.checkTing = function(player, cid, require_menchin)
  local result = {}
  
  -- 获取当前手牌（不包括已副露的牌）
  local handCards = table.simpleClone(KleeU.getHandCards(player, 0))
  
  -- 如果需要打出一张牌，则从手牌中移除该牌
  if cid then
    handCards = table.filter(handCards, function(id) return id ~= cid end)
  end
  
  -- 修正：无论是否传入cid，最终手牌都应该是13张
  if require_menchin and #handCards ~= 13 then
    return result
  end
  
  -- 将手牌转换为牌表格式
  local handCardsTable = {}
  for _, id in ipairs(handCards) do
    local card = Fk:getCardById(id)
    table.insert(handCardsTable, {
      suit = KleeU.getSuit(card),
      number = card.number
    })
  end
  
  -- 遍历所有可能的牌（万、饼、条1-9，字牌1-7）
  for _, suit in ipairs({"m", "p", "s"}) do
    for number = 1, 9 do
      -- 创建一个包含当前手牌和虚拟牌的完整牌表
      local testCards = table.simpleClone(handCardsTable)
      table.insert(testCards, {suit = suit, number = number})
      
      -- 检查是否能和牌
      if KleeU.ifRongWithHand(testCards) then
        table.insert(result, {suit = suit, number = number})
      end
    end
  end
  
  for number = 1, 7 do
    -- 创建一个包含当前手牌和虚拟牌的完整牌表
    local testCards = table.simpleClone(handCardsTable)
    table.insert(testCards, {suit = "z", number = number})
    
    if KleeU.ifRongWithHand(testCards) then
      table.insert(result, {suit = "z", number = number})
    end
  end
  
  return result
end


--- 判断给定的牌表是否能和牌
--- @param cards table @牌表，每个元素为{suit=花色, number=点数}
--- @return boolean
KleeU.ifRongWithHand = function(cards)
  -- 将牌按花色和点数排序
  table.sort(cards, function(a, b)
    -- 先按花色排序：m→p→s→z
    local suitOrder = {m = 1, p = 2, s = 3, z = 4}
    if a.suit ~= b.suit then
      return suitOrder[a.suit] < suitOrder[b.suit]
    end
    -- 同花色按点数排序
    return a.number < b.number
  end)
  
  -- 检查是否是国士无双（十三幺）
  local function isThirteenOrphans(cards)
    -- 国士无双需要的牌型：1m,9m,1p,9p,1s,9s,1z,2z,3z,4z,5z,6z,7z + 任意一张这些牌
    local requiredTiles = {
      {suit = "m", number = 1},
      {suit = "m", number = 9},
      {suit = "p", number = 1},
      {suit = "p", number = 9},
      {suit = "s", number = 1},
      {suit = "s", number = 9},
      {suit = "z", number = 1},
      {suit = "z", number = 2},
      {suit = "z", number = 3},
      {suit = "z", number = 4},
      {suit = "z", number = 5},
      {suit = "z", number = 6},
      {suit = "z", number = 7}
    }
    
    for _, reqTile in ipairs(requiredTiles) do
      local found = false
      for _, card in ipairs(cards) do
        if card.suit == reqTile.suit and card.number == reqTile.number then
          found = true
          break
        end
      end
      if not found then
        return false
      end
    end
    
    -- 检查是否有一张额外的牌（必须是必需牌之一）
    if #cards == 14 then
      for _, card in ipairs(cards) do
        local isExtra = true
        for _, reqTile in ipairs(requiredTiles) do
          if card.suit == reqTile.suit and card.number == reqTile.number then
            isExtra = false
            break
          end
        end
        if isExtra then
          return false -- 包含非必需牌
        end
      end
      return true -- 14张牌且都是必需牌
    end
    
    return false
  end
  
  -- 检查是否是七对子
  local function isSevenPairs(cards)
    if #cards ~= 14 then
      return false
    end
    
    -- 统计每种牌的数量
    local countMap = {}
    for _, card in ipairs(cards) do
      local key = card.suit .. "_" .. card.number
      countMap[key] = (countMap[key] or 0) + 1
    end
    
    -- 检查是否有7个对子
    local pairCount = 0
    for _, count in pairs(countMap) do
      if count == 2 then
        pairCount = pairCount + 1
      elseif count ~= 0 then
        return false -- 有单张或三张的牌
      end
    end
    
    return pairCount == 7
  end
  
  -- 检查标准牌型（雀头+顺子/刻子）
  local function isStandardWin(cards)
    -- 递归函数：尝试分解牌组为雀头+顺子/刻子
    local function decompose(cards, hasPair)
      if #cards == 0 then
        return true
      end
      
      -- 尝试取雀头
      if not hasPair and #cards >= 2 and cards[1].suit == cards[2].suit and cards[1].number == cards[2].number then
        local newCards = {}
        for i = 3, #cards do
          table.insert(newCards, cards[i])
        end
        if decompose(newCards, true) then
          return true
        end
      end
      
      -- 尝试取刻子
      if #cards >= 3 and cards[1].suit == cards[2].suit and cards[1].suit == cards[3].suit and
         cards[1].number == cards[2].number and cards[1].number == cards[3].number then
        local newCards = {}
        for i = 4, #cards do
          table.insert(newCards, cards[i])
        end
        if decompose(newCards, hasPair) then
          return true
        end
      end
      
      -- 尝试取顺子（字牌不能组成顺子）
      if cards[1].suit ~= "z" then
        -- 找出连续的三张牌
        local foundIndex2, foundIndex3
        for i = 2, #cards do
          if cards[i].suit == cards[1].suit and cards[i].number == cards[1].number + 1 then
            foundIndex2 = i
            break
          end
        end
        
        if foundIndex2 then
          for i = foundIndex2 + 1, #cards do
            if cards[i].suit == cards[1].suit and cards[i].number == cards[1].number + 2 then
              foundIndex3 = i
              break
            end
          end
        end
        
        if foundIndex2 and foundIndex3 then
          local newCards = {}
          -- 复制除了这三张牌以外的所有牌
          for i = 1, #cards do
            if i ~= 1 and i ~= foundIndex2 and i ~= foundIndex3 then
              table.insert(newCards, cards[i])
            end
          end
          if decompose(newCards, hasPair) then
            return true
          end
        end
      end
      return false
    end
    return decompose(cards, false)
  end

  if #cards == 14 then
    -- 先检查国士无双
    if isThirteenOrphans(cards) then
      return true
    end
    
    -- 再检查七对子
    if isSevenPairs(cards) then
      return true
    end
  end
    
  -- 最后检查标准牌型
  return isStandardWin(cards)
end

--- 判断玩家是否能荣和/自摸
--- @param player Player
--- @param cid integer|table|nil @牌ID（nil表示自摸）
--- @return boolean
KleeU.ifRong = function(player, cid)
  -- 获取玩家手牌（不包括已副露的牌）
  local handCards = table.simpleClone(KleeU.getHandCards(player, 0))
  
  -- 将手牌转换为牌表格式
  local cards = {}
  for _, id in ipairs(handCards) do
    local card = Fk:getCardById(id)
    table.insert(cards, {
      suit = KleeU.getSuit(card),
      number = card.number - 13
    })
  end
  
  -- 如果要和的牌不为nil，则加入牌表
  if cid then
    -- 处理虚拟牌（表形式）
    if type(cid) == "table" then
      table.insert(cards, cid)
    else
      -- 处理真实牌ID
      local card = Fk:getCardById(cid)
      table.insert(cards, {
        suit = KleeU.getSuit(card),
        number = card.number - 13
      })
    end
  end
  
  return KleeU.ifRongWithHand(cards)
end

---执行胜利
---@param players ServerPlayer[] @执行者
---@param is_zimo boolean @是否自摸
KleeU.win = function (players, is_zimo)
  local room = players[1].room
  --算分
  --洗牌摸牌
  for _, p in ipairs(room.players) do
    for _, cid in ipairs(p:getCardIds("h")) do
      local c = Fk:getCardById(cid)
      room:setCardMark(c, "@@Chow", 0)
      room:setCardMark(c, "@@Pung", 0)
      room:setCardMark(c, "@@Kong", 0)
    end
    p:clearPiles()
    room:throwCard(p:getCardIds(Player.Hand), "#mahjong_que_rule&", p)
  end
  room:shuffleDrawPile()
  for _, p in ipairs(room.players) do
    p:drawCards(13)
  end
  --切换到对应位置
  local banker = room:getPlayerById(room:getBanner("banker"))
  if not table.contains(players, banker) then
    banker = banker.next
    room:setBanner("banker", banker.id)
    room:setBanner("@banker", banker._splayer:getScreenName())
    room:setBanner("sit", (room:getBanner("sit") % 4) + 1)
    if room:getBanner("sit") == 1 then
      room:setBanner("@round_times", room:getBanner("@round_times") + 1)
      room:setBanner("@roomwind", "mahjong_z"..((room:getBanner("@round_times") - 1) % 4 + 1))
    end
  end

  local jump = banker
  jump = jump:getLastAlive()
  while true do
    if jump == room.current then
      break
    else
      room:setPlayerMark(jump, "jump_round", 1)
      jump = jump:getLastAlive()
    end
  end
  room:endTurn()
end

---获得牌河
---@param player Player
---@return integer[]
KleeU.getCardRiver = function (player)
  return player:getPile("card_river")
end

return KleeU